package com.ithui.tidal.websocket.domain.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.ithui.tidal.user.dao.UserDao;
import com.ithui.tidal.user.domain.entity.User;
import com.ithui.tidal.user.service.LoginService;
import com.ithui.tidal.websocket.domain.dto.WSChannelExtraDTO;
import com.ithui.tidal.websocket.domain.service.WebSocketService;
import com.ithui.tidal.websocket.domain.service.adapter.WebSocketAdapter;
import com.ithui.tidal.websocket.domain.vo.resp.WSBaseResp;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import lombok.SneakyThrows;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.result.WxMpQrCodeTicket;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.time.Duration;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 *@Author: ithui
 *@CreateTime: 2025-07-30
 * @Description: 专门管理WebSocket的逻辑，包括推拉消息，心跳维护等
 */
@Service
public class WebSocketServiceImpl implements WebSocketService {

    @Autowired
    @Lazy
    private WxMpService wxMpService;

    @Autowired
    private UserDao userDao;

    @Autowired
    private LoginService loginService;


    /**
     * 管理所有在线用户的连接，包括登录态和游客
     * channel 和 code 映射关系
     */
    private static final ConcurrentHashMap<Channel, WSChannelExtraDTO> ONLINE_WS_MAP = new ConcurrentHashMap<>();

    public static final int MAXIMUM_SIZE = 10000;
    public static final Duration DURATION = Duration.ofHours(1); // 1小时

    /**
     * 临时保存登录code和channel的映射关系
     */
    private static final Cache<Integer,Channel> WAIT_LOGIN_MAP = CacheBuilder.newBuilder()
            .maximumSize(MAXIMUM_SIZE) // 最大容量
            .expireAfterWrite(DURATION) // 过期时间 1小时
            .build();

    @Override
    public void connect(Channel channel) {
        // 保存链接
        ONLINE_WS_MAP.put(channel, new WSChannelExtraDTO());
    }

    @SneakyThrows
    @Override
    public void handleLoginReq(Channel channel) {
        // 1. 生成随机码
        Integer code = generateLoginCode(channel);
        // 2. 找微信申请带参二维码
        WxMpQrCodeTicket wxMpQrCodeTicket = wxMpService.getQrcodeService().qrCodeCreateTmpTicket(code, (int) DURATION.getSeconds());
        // 3. 把二维码推送给前端
        sendMsg(channel,WebSocketAdapter.buildResp(wxMpQrCodeTicket));
    }

    /**
     * 用户下线
     * @param channel
     */
    @Override
    public void remove(Channel channel) {
        ONLINE_WS_MAP.remove(channel);
        // TODO 用户下线
    }

    /**
     * 用户登录
     * @param code
     * @param uid
     */
    @Override
    public void scanLoginSuccess(Integer code, Long uid) {
        // 确认链接在机器上
        Channel channel = WAIT_LOGIN_MAP.getIfPresent(code);
        if (Objects.isNull(channel)) {
            return;
        }
        // 通过uid获取用户信息
        User user = userDao.getById(uid);
        // 移除code
        WAIT_LOGIN_MAP.invalidate(code);
        // 调用登录模块获取token
        String token = loginService.login(uid);
        // 发送消息
        sendMsg(channel,WebSocketAdapter.buildResp(user,token));
    }

    @Override
    public void waitAuthorize(Integer code) {
        Channel channel = WAIT_LOGIN_MAP.getIfPresent(code);
        if(Objects.isNull(channel)){
            return;
        }
        sendMsg(channel,WebSocketAdapter.buildWaitAuthorizeResp());
    }


    /**
     * 发送消息
     * @param channel 通道
     * @param resp 响应对象
     */
    private void sendMsg(Channel channel, WSBaseResp<?> resp) {
        channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(resp)));
    }

    private Integer generateLoginCode(Channel channel) {
        Integer code;
        do{
            // 生成随机码
            code = RandomUtil.randomInt(Integer.MAX_VALUE);
        }while (Objects.nonNull(WAIT_LOGIN_MAP.asMap().putIfAbsent(code, channel)));
        return code;
    }
}
